﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;

namespace UdfFactory
{
    // UDF allows all characters except NUL in paths and filenames, and I've decided to not break with
    // the standard on this one. This means that trying to create a UdfDirectory with a path of "foo/baz" 
    // will NOT create two directories "foo" and "baz", it will create one awkward directory named 
    // "foo/baz". Similarly, creating a file named "foo/baz.bar" will put a forward slash in the filename,
    // which is generally considered to be a Bad Thing, and also quite rude. You have been warned.

    // TODO: Implement UDF aliases and named streams.

    public class UdfObject
    {
        /// <summary>The name of this object. All characters except NUL are permitted, although some may be disallowed by the target OS.</summary>
        protected string Name;
        /// <summary>The PID of this object. Set to 0xFFFF if unused.</summary>
        protected uint Pid;
        /// <summary>The GID of this object. Set to 0xFFFF if unused.</summary>
        protected uint Gid;
        /// <summary>The permissions assigned to this object. Defined in ECMA-167 4/14.9.5, NOT standard POSIX permissions. Set to 0x7FFF if unused.</summary>
        protected uint Permissions;
        /// <summary>The creation time of this object, in local time. Set to DateTime.Now if unused.</summary>        
        protected DateTime Timestamp; 
    }
    public class UdfFile : UdfObject
    {
        public UdfFile(string Name, Stream Data) : this(Name, Data, 0xFFFF, 0xFFFF, 0x7FFF) { }
        public UdfFile(string Name, Stream Data, uint Pid, uint Gid, uint Permissions) : this(Name, Data, Pid, Gid, Permissions, DateTime.Now) { }
        public UdfFile(string Name, Stream Data, uint Pid, uint Gid, uint Permissions, DateTime Timestamp)
        {
            this.Name = Name;
            this.Data = Data;
            this.Pid = Pid;
            this.Gid = Gid;
            this.Permissions = Permissions;
            this.Timestamp = Timestamp;
        }
        /// <summary>The primary data stream of this file.</summary>
        Stream Data;

        /// <summary>A lossy method for translating UDF permissions to POSIX permissions and vice-versa. POSIX write grants UDF write, delete, and change attributes.</summary>
        uint PosixPermissions
        {
            get 
            {
                BitArray udf = BitFactory.Convert(Permissions);
                uint output = 0x0000;
                if (udf[0])
                    output |= 0x0001;
                if (udf[1])
                    output |= 0x0002;
                if (udf[2])
                    output |= 0x0004;
                if (udf[5])
                    output |= 0x0010;
                if (udf[6])
                    output |= 0x0020;
                if (udf[7])
                    output |= 0x0040;
                if (udf[10])
                    output |= 0x0100;
                if (udf[11])
                    output |= 0x0200;
                if (udf[12])
                    output |= 0x0400;
                return output;
            }
            set 
            {
                BitArray posix = BitFactory.Convert(value);
                Permissions = 0x00000000;
                if(posix[0])
                    Permissions |= 0x00000001;
                if(posix[1])
                    Permissions |= 0x0000001A;
                if(posix[2])
                    Permissions |= 0x00000004;
                if(posix[4])
                    Permissions |= 0x00000020;
                if(posix[5])
                    Permissions |= 0x00000340;
                if(posix[6])
                    Permissions |= 0x00000080;
                if(posix[8])
                    Permissions |= 0x00000400;
                if(posix[9])
                    Permissions |= 0x00006800;
                if(posix[10])
                    Permissions |= 0x00001000;
            }
        }
    }
    public class UdfDirectory : UdfObject
    {
        public UdfDirectory(string Name) : this(Name, 0xFFFF, 0xFFFF, 0x7FFF, DateTime.Now) { }
        public UdfDirectory(string Name, uint Pid, uint Gid, uint Permissions, DateTime Timestamp) : this(Name, Pid, Gid, Permissions, DateTime.Now, new List<UdfObject>()) { }
        public UdfDirectory(string Name, uint Pid, uint Gid, uint Permissions, DateTime Timestamp, List<UdfObject> Children)
        {
            this.Name = Name;
            this.Pid = Pid;
            this.Gid = Gid;
            this.Permissions = Permissions;
            this.Timestamp = Timestamp;
            this.Children = Children;
        }
        /// <summary>A list of UdfObjects contained by this directory.</summary>
        List<UdfObject> Children;
    }
}
